//
// Copyright (C) 2011 Steve Channell steve.channell@cepheis.com
//
// This file is part of Cephei.QL, an open-source library wrapper 
// arround QuantLib http://quantlib.org/
//
// Cephei.QL is open source software: you can redistribute it and/or modify it
// under the terms of the license.  You should have received a
// copy of the license along with this program; if not, please email
// <support@cepheis.com>. The license is also available online at
// <http://cepheis.com/license.htm>.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE.  See the license for more details.
//
// Version 2.101
//#include "stdafx.h"
#include "NthToDefault.h"
using namespace Cephei::QL::Experimental::Credit;
#include <gen/QL/Times/DayCounter.h>
#include <gen/QL/Termstructures/DefaultProbabilityTermStructure.h>
#include <gen/QL/Experimental/Credit/OneFactorCopula.h>
#include <gen/QL/Times/Schedule.h>
#include <gen/QL/Termstructures/YieldTermStructure.h>
#include <gen/QL/Times/Period.h>
#include <gen/QL/Instruments/Claim.h>
#include <gen/QL/PricingEngine.h>
#include <gen/QL/Instrument.h>
using namespace Cephei::QL::Times;
using namespace Cephei::QL::Termstructures;
using namespace Cephei::QL::Instruments;
using namespace Cephei::QL;
#define HANDLE
#undef ABSTRACT
#undef STRUCT
Cephei::QL::Experimental::Credit::CNthToDefault::CNthToDefault (UInt64 n, Cephei::IVector<Cephei::QL::Termstructures::IDefaultProbabilityTermStructure^>^ probabilities, Double recoveryRate, Cephei::QL::Experimental::Credit::IOneFactorCopula^ copula, QL::Protection::SideEnum side, Double nominal, Cephei::QL::Times::ISchedule^ premiumSchedule, Double premiumRate, Cephei::QL::Times::IDayCounter^ dayCounter, Boolean settlePremiumAccrual, Cephei::QL::Termstructures::IYieldTermStructure^ yieldTS, Cephei::QL::Times::IPeriod^ integrationStepSize, Microsoft::FSharp::Core::FSharpOption<Cephei::QL::Instruments::IClaim^>^ claim, Cephei::QL::IPricingEngine^ QL_Pricer) : CInstrument(CNthToDefault::typeid)
{
    CoVector<Cephei::QL::Termstructures::IDefaultProbabilityTermStructure^>^ _Cprobabilities;
    COneFactorCopula^ _Ccopula;
    CSchedule^ _CpremiumSchedule;
    CDayCounter^ _CdayCounter;
    CYieldTermStructure^ _CyieldTS;
    CPeriod^ _CintegrationStepSize;
    CClaim^ _Cclaim;
    try
    {
#ifdef HANDLE
        _phNthToDefault = NULL;
#endif
        QuantLib::Size _n = (QuantLib::Size)ValueHelper::Convert (n);
        _Cprobabilities = safe_cast<CoVector<Cephei::QL::Termstructures::IDefaultProbabilityTermStructure^>^> (probabilities);
        _Cprobabilities ->Lock ();
        INativeVector<Cephei::QL::Termstructures::IDefaultProbabilityTermStructure^>^ _NCIprobabilities = _Cprobabilities->getFeature (NativeFeature::Handle);
        CDefaultProbabilityTermStructureVector^ _NCprobabilities = safe_cast<CDefaultProbabilityTermStructureVector^>(_NCIprobabilities);
        std::vector<Handle<QuantLib::DefaultProbabilityTermStructure> >& _probabilities = static_cast<std::vector<Handle<QuantLib::DefaultProbabilityTermStructure> >&> (_NCprobabilities->GetHandle ());
        QuantLib::Real _recoveryRate = (QuantLib::Real)ValueHelper::Convert (recoveryRate);
        _Ccopula = safe_cast<COneFactorCopula^> (copula);
        _Ccopula->Lock();
        Handle<QuantLib::OneFactorCopula>& _copula = static_cast<Handle<QuantLib::OneFactorCopula>&> (_Ccopula->GetHandle ()); 
        QuantLib::Protection::Side _side = (QuantLib::Protection::Side)side ;
        QuantLib::Real _nominal = (QuantLib::Real)ValueHelper::Convert (nominal);
        _CpremiumSchedule = safe_cast<CSchedule^> (premiumSchedule);
        _CpremiumSchedule->Lock();
        QuantLib::Schedule& _premiumSchedule = static_cast<QuantLib::Schedule&> (_CpremiumSchedule->GetReference ()); 
        QuantLib::Rate _premiumRate = (QuantLib::Rate)ValueHelper::Convert (premiumRate);
        _CdayCounter = safe_cast<CDayCounter^> (dayCounter);
        _CdayCounter->Lock();
        QuantLib::DayCounter& _dayCounter = static_cast<QuantLib::DayCounter&> (_CdayCounter->GetReference ()); 
        bool _settlePremiumAccrual = (bool)ValueHelper::Convert (settlePremiumAccrual);
        _CyieldTS = safe_cast<CYieldTermStructure^> (yieldTS);
        _CyieldTS->Lock();
        Handle<QuantLib::YieldTermStructure>& _yieldTS = static_cast<Handle<QuantLib::YieldTermStructure>&> (_CyieldTS->GetHandle ()); 
        _CintegrationStepSize = safe_cast<CPeriod^> (integrationStepSize);
        _CintegrationStepSize->Lock();
        QuantLib::Period& _integrationStepSize = static_cast<QuantLib::Period&> (_CintegrationStepSize->GetReference ()); 
        if (Microsoft::FSharp::Core::FSharpOption<Cephei::QL::Instruments::IClaim^>::IsSome::get (claim))
        {
            _Cclaim = safe_cast<CClaim^> (claim->Value);
            _Cclaim->Lock();
        }
        boost::shared_ptr<QuantLib::Claim> _claim = 
            (Microsoft::FSharp::Core::FSharpOption<Cephei::QL::Instruments::IClaim^>::IsSome::get (claim) ? static_cast<boost::shared_ptr<QuantLib::Claim>> (_Cclaim->GetShared ()) : boost::shared_ptr<QuantLib::Claim>()); //1
        _ppNthToDefault = new boost::shared_ptr<QuantLib::NthToDefault> (new QuantLib::NthToDefault ( _n,  _probabilities,  _recoveryRate,  _copula,  _side,  _nominal,  _premiumSchedule,  _premiumRate,  _dayCounter,  _settlePremiumAccrual,  _yieldTS,  _integrationStepSize,  _claim ));
        CPricingEngine^ _CQL_Pricer = safe_cast<CPricingEngine^> (QL_Pricer);
        boost::shared_ptr<QuantLib::PricingEngine>& _QL_Pricer = static_cast<boost::shared_ptr<QuantLib::PricingEngine>&> (_CQL_Pricer->GetShared ());
        (*_ppNthToDefault)->setPricingEngine (_QL_Pricer);
        SetInstrument (boost::dynamic_pointer_cast<QuantLib::Instrument> (*_ppNthToDefault));
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown std::exception"));
	}
    finally
    {
        if (_Cprobabilities != nullptr) _Cprobabilities->Unlock();
        if (_Ccopula != nullptr) _Ccopula->Unlock();
        if (_CpremiumSchedule != nullptr) _CpremiumSchedule->Unlock();
        if (_CdayCounter != nullptr) _CdayCounter->Unlock();
        if (_CyieldTS != nullptr) _CyieldTS->Unlock();
        if (_CintegrationStepSize != nullptr) _CintegrationStepSize->Unlock();
        if (_Cclaim != nullptr) _Cclaim->Unlock();
    }
}
Cephei::QL::Experimental::Credit::CNthToDefault::CNthToDefault (boost::shared_ptr<QuantLib::NthToDefault>& childNative, Object^ owner) : CInstrument(CNthToDefault::typeid)
{
#ifdef HANDLE
	_phNthToDefault = NULL;
#endif
	_ppNthToDefault = &childNative;
    _ppInstrument = new boost::shared_ptr<QuantLib::Instrument> (boost::dynamic_pointer_cast<QuantLib::Instrument> (*_ppNthToDefault));
}
Cephei::QL::Experimental::Credit::CNthToDefault::CNthToDefault (QuantLib::NthToDefault& childNative, Object^ owner) : CInstrument(CNthToDefault::typeid)
{
#ifdef HANDLE
	_phNthToDefault = NULL;
#endif
	_ppNthToDefault = new boost::shared_ptr<QuantLib::NthToDefault> (&childNative);
    _ppInstrument = new boost::shared_ptr<QuantLib::Instrument> (boost::dynamic_pointer_cast<QuantLib::Instrument> (*_ppNthToDefault));
    _NthToDefaultOwner = owner;
    _InstrumentOwner = owner;
}

Cephei::QL::Experimental::Credit::CNthToDefault::CNthToDefault (CNthToDefault^ copy) : CInstrument(CNthToDefault::typeid)
{
#ifdef HANDLE
	_phNthToDefault = NULL;
#endif
	if (copy->HasNative() != NULL)
    {
		_ppNthToDefault = new boost::shared_ptr<QuantLib::NthToDefault> (copy->GetShared());
        _ppInstrument = new boost::shared_ptr<QuantLib::Instrument> (boost::dynamic_pointer_cast<QuantLib::Instrument> (*_ppNthToDefault));
    }
}
Cephei::QL::Experimental::Credit::CNthToDefault::CNthToDefault (System::Type^ t) : CInstrument(CNthToDefault::typeid)
{
#ifdef HANDLE
	_phNthToDefault = NULL;
#endif
	if (!t->IsSubclassOf(CNthToDefault::typeid))
		throw gcnew Exception ("Invalid base-case init");
}
#ifdef HANDLE
Cephei::QL::Experimental::Credit::CNthToDefault::CNthToDefault (QuantLib::Handle<QuantLib::NthToDefault>& childNative, Object^ owner)  : CInstrument(CNthToDefault::typeid)
{
	_phNthToDefault = &childNative;
	_ppNthToDefault = &static_cast<boost::shared_ptr<QuantLib::NthToDefault>>(childNative.currentLink());
    _ppInstrument = new boost::shared_ptr<QuantLib::Instrument> (boost::dynamic_pointer_cast<QuantLib::Instrument> (*_ppNthToDefault));
    _NthToDefaultOwner = owner;
}
Cephei::QL::Experimental::Credit::CNthToDefault::CNthToDefault (QuantLib::Handle<QuantLib::NthToDefault> childNative)  : CInstrument(CNthToDefault::typeid)
{
	_phNthToDefault = &childNative;
	_ppNthToDefault = &static_cast<boost::shared_ptr<QuantLib::NthToDefault>>(childNative.currentLink());
    _ppInstrument = new boost::shared_ptr<QuantLib::Instrument> (boost::dynamic_pointer_cast<QuantLib::Instrument> (*_ppNthToDefault));
}
#endif
#ifdef STRUCT
Cephei::QL::Experimental::Credit::CNthToDefault::CNthToDefault (QuantLib::NthToDefault childNative)  : CInstrument(CNthToDefault::typeid)
{
#ifdef HANDLE
	_phNthToDefault = NULL;
#endif
	_ppNthToDefault = new boost::shared_ptr<QuantLib::NthToDefault> (new QuantLib::NthToDefault (childNative));
    _ppInstrument = new boost::shared_ptr<QuantLib::Instrument> (boost::dynamic_pointer_cast<QuantLib::Instrument> (*_ppNthToDefault));
}
#endif

Cephei::QL::Experimental::Credit::CNthToDefault::~CNthToDefault ()
{
    if (_ppNthToDefault != NULL)
    {
	    delete _ppNthToDefault;
        _ppNthToDefault = NULL;
    }
}
Cephei::QL::Experimental::Credit::CNthToDefault::!CNthToDefault ()
{
    if (_ppNthToDefault != NULL)
    {
	    delete _ppNthToDefault;
    }
}
QuantLib::NthToDefault& Cephei::QL::Experimental::Credit::CNthToDefault::GetReference ()
{
    if (_ppNthToDefault == NULL) throw gcnew NativeNullException ();
	return **_ppNthToDefault;
}
boost::shared_ptr<QuantLib::NthToDefault>& Cephei::QL::Experimental::Credit::CNthToDefault::GetShared ()
{
    if (_ppNthToDefault == NULL) throw gcnew NativeNullException ();
	return *_ppNthToDefault;
}
QuantLib::NthToDefault* Cephei::QL::Experimental::Credit::CNthToDefault::GetPointer ()
{
    if (_ppNthToDefault == NULL) throw gcnew NativeNullException ();
	return &**_ppNthToDefault;
}
#ifdef HANDLE
QuantLib::Handle<QuantLib::NthToDefault>& Cephei::QL::Experimental::Credit::CNthToDefault::GetHandle ()
{
	if (_phNthToDefault == NULL)
	{
		_phNthToDefault = new Handle<QuantLib::NthToDefault> (*_ppNthToDefault);
	}
	return *_phNthToDefault;
}
#endif
bool Cephei::QL::Experimental::Credit::CNthToDefault::HasNative () 
{
	return (_ppNthToDefault != NULL);
}

UInt64 Cephei::QL::Experimental::Credit::CNthToDefault::BasketSize::get ()
{
    try
    {
    	QuantLib::Size _rv = (QuantLib::Size)(*_ppNthToDefault)->basketSize ( );   
        UInt64 _nrv = (UInt64)ValueHelper::Convert (_rv);
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown std::exception"));
	}
    finally
    {
    }
}
Cephei::QL::Times::IDayCounter^ Cephei::QL::Experimental::Credit::CNthToDefault::DayCounter::get ()
{
    try
    {
    	QuantLib::DayCounter _rv = (QuantLib::DayCounter)(*_ppNthToDefault)->dayCounter ( );   
        Cephei::QL::Times::CDayCounter^ _nrv = gcnew Cephei::QL::Times::CDayCounter (_rv);
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown std::exception"));
	}
    finally
    {
    }
}
Double Cephei::QL::Experimental::Credit::CNthToDefault::FairPremium::get ()
{
    try
    {
    	QuantLib::Rate _rv = (QuantLib::Rate)(*_ppNthToDefault)->fairPremium ( );   
        Double _nrv = (Double)ValueHelper::Convert (_rv);
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown std::exception"));
	}
    finally
    {
    }
}
Boolean Cephei::QL::Experimental::Credit::CNthToDefault::IsExpired::get ()
{
    try
    {
    	bool _rv = (bool)(*_ppNthToDefault)->isExpired ( );   
        Boolean _nrv = (Boolean)ValueHelper::Convert (_rv);
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown std::exception"));
	}
    finally
    {
    }
}
Double Cephei::QL::Experimental::Credit::CNthToDefault::Nominal::get ()
{
    try
    {
    	QuantLib::Real _rv = (QuantLib::Real)(*_ppNthToDefault)->nominal ( );   
        Double _nrv = (Double)ValueHelper::Convert (_rv);
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown std::exception"));
	}
    finally
    {
    }
}
Double Cephei::QL::Experimental::Credit::CNthToDefault::Premium::get ()
{
    try
    {
    	QuantLib::Rate _rv = (QuantLib::Rate)(*_ppNthToDefault)->premium ( );   
        Double _nrv = (Double)ValueHelper::Convert (_rv);
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown std::exception"));
	}
    finally
    {
    }
}
UInt64 Cephei::QL::Experimental::Credit::CNthToDefault::Rank::get ()
{
    try
    {
    	QuantLib::Size _rv = (QuantLib::Size)(*_ppNthToDefault)->rank ( );   
        UInt64 _nrv = (UInt64)ValueHelper::Convert (_rv);
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown std::exception"));
	}
    finally
    {
    }
}
QL::Protection::SideEnum Cephei::QL::Experimental::Credit::CNthToDefault::Side::get ()
{
    try
    {
    	QuantLib::Protection::Side _rv = (QuantLib::Protection::Side)(*_ppNthToDefault)->side ( );   
        QL::Protection::SideEnum _nrv = (QL::Protection::SideEnum)_rv;
    	return _nrv;
	}
    catch (QuantLib::Error& _error)
    {
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown quantlib error"));
        
    }
	catch (std::exception& _error)
	{
        if (_error.what())
		    throw gcnew NativeExcpetion (gcnew System::String(_error.what()));
        else
		    throw gcnew NativeExcpetion (gcnew System::String("Unknown std::exception"));
	}
    finally
    {
    }
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Factory class

Cephei::QL::Experimental::Credit::INthToDefault^ Cephei::QL::Experimental::Credit::CNthToDefault_Factory::Create (UInt64 n, Cephei::IVector<Cephei::QL::Termstructures::IDefaultProbabilityTermStructure^>^ probabilities, Double recoveryRate, Cephei::QL::Experimental::Credit::IOneFactorCopula^ copula, QL::Protection::SideEnum side, Double nominal, Cephei::QL::Times::ISchedule^ premiumSchedule, Double premiumRate, Cephei::QL::Times::IDayCounter^ dayCounter, Boolean settlePremiumAccrual, Cephei::QL::Termstructures::IYieldTermStructure^ yieldTS, Cephei::QL::Times::IPeriod^ integrationStepSize, Microsoft::FSharp::Core::FSharpOption<Cephei::QL::Instruments::IClaim^>^ claim, Cephei::QL::IPricingEngine^ QL_Pricer)
{
    return gcnew CNthToDefault ( n,  probabilities,  recoveryRate,  copula,  side,  nominal,  premiumSchedule,  premiumRate,  dayCounter,  settlePremiumAccrual,  yieldTS,  integrationStepSize,  claim,  QL_Pricer);
}
